#!/bin/bash
BASE_HOME=$(dirname "$0")
source ${BASE_HOME}/common_setup  # Loading the common code section from 'common_setup', and 'common_setup' in turn loads the shared functions from 'common_functions'.

#slave 
slaveIP=${REMOTE_HOST}
log_info "Switching MySQL from master node ${LOCAL_HOST} to slave node ${REMOTE_HOST} due to Keepalived entering fault status"

BINLOG_PATH=$(dirname ${LOCAL_BINLOG})
log_info "Local MySQL node binlog path is ${BINLOG_PATH}"

# Check if the VIP is on this node, and if it is, this node is the master.
WVIP_COUNT=$(ip addr | grep -c "${WRITE_VIP}")
if (( ${WVIP_COUNT} == 1 )); then
    log_info "This MySQL node ${LOCAL_HOST} is master. Continuing with switch."
    log_info "VIP $(ip addr | grep -v grep | grep \"${WRITE_VIP}\")"
else
    log_info "VIP ${WRITE_VIP} not present on local host. So this MySQL node is slave, no need to switch."
		   
fi

# Create binlog parse to SQL work dir if not exists						
[[ ! -d ${sqlpath} ]] && mkdir -p ${sqlpath}


#clear the files
> ${sqlpath}/sync.sql
> ${sqlpath}/sync_file
> ${sqlpath}/tmp.txt

LAST_BLOGFILE=$(ls -l ${LOCAL_BINLOG}.* | grep -v "index" | tail -n1 | awk '{print $NF}')
LAST_BLOGFILEN=$(basename ${LAST_BLOGFILE})
log_info "Local MySQL last binlog file is ${LAST_BLOGFILE}. Last binlog number is ${LAST_BLOGFILEN}"

# Show slave master status
log_info "CMD: show master status (on remote slave)"
${MYSQL_REMOTE_CMD} -e "show master status \G" > ${sqlpath}/master.txt
cat ${sqlpath}/master.txt

getstatus(){

# slave status
${MYSQL_REMOTE_CMD} -e "show slave status \G" > ${sqlpath}/tmp.txt

# Master_Log_File
READFILE=$(grep -w "Master_Log_File" ${sqlpath}/tmp.txt | grep -v "Relay" | awk -F": " '{print $2}')

#Relay_Master_Log_File
EXECFILE=$(grep -w "Relay_Master_Log_File" ${sqlpath}/tmp.txt | grep "Relay" | awk -F": " '{print $2}')

# Exec_Master_Log_Pos
EXECPOS=$(grep -w 'Exec_Master_Log_Pos' ${sqlpath}/tmp.txt | awk -F ': ' '{print $2}')

# Read_Master_Log_Pos
READPOS=$(grep -w "Read_Master_Log_Pos" ${sqlpath}/tmp.txt | awk -F ': ' '{print $2}')

# Get master binlog endpos
MASTERENDPOS=$(${MYSQLBINLOG_CMD} ${LAST_BLOGFILE} |  grep 'end_log_pos' | tail -n1 | awk -F ' ' '{print $7}')

log_info "master_binlogfile_endpos:${MASTERENDPOS}"
log_info "slave_readpos:${READPOS}"
log_info "slave_execpos:${EXECPOS}"
log_info "slave_readfile:${READFILE}"
log_info "slave_execfile:${EXECFILE}"
log_info "master_blogfile:${LAST_BLOGFILEN}"
}

getstatus

returnstatus(){
    log_info "slave_readfile=${READFILE} != slave_execfile=${EXECFILE} or slave_readpos=${READPOS} != slave_execpos=${EXECPOS},waiting 5s for SQL_thread to catch up with IO_thread"
    sleep 5
    getstatus
}

# Get slave status of sql_thread
SQL_STATUS=$(grep -w  "Slave_SQL_Running" "${sqlpath}/tmp.txt" | awk -F": " '{print $2}')
if [[ -z "${SQL_STATUS}" ]]; then
    log_warn "Local mysql ${LOCAL_HOST} is slave and Slave_SQL_Running:${SQL_STATUS}"
    log_warn "No need to switch and the local node is slave and exit fault scripts running"
    exit 1
else
    log_info "Slave_SQL_Running:${SQL_STATUS}"
fi

##set remote mysql read_only
log_info "Set remote host ${REMOTE_HOST} mysql read_only=on and super_read_only=on"
${MYSQL_REMOTE_CMD} -N -L -s -e "set  global super_read_only=ON;set global read_only=ON;show variables like '%read_only';"

# Use mysqlbinlog to created slave io_thread is not sync master binlog file and parse to sql file
if (( MASTERENDPOS != READPOS )); then
    if [[ LAST_BLOGFILEN == READFILE ]]; then
        FILE_TO_SYNC=${LAST_BLOGFILE}
    else
        FILE_TO_SYNC=${BINLOG_PATH}/${READFILE}
    fi
    log_info "Slave node ${REMOTE_HOST} not sync completed from master node ${LOCAL_HOST} and started parse master node binlog file ${MYSQLBINLOG_CMD} --start-position  ${READPOS} ${FILE_TO_SYNC} > ${sqlpath}/sync.sql"
    ${MYSQLBINLOG_CMD} --start-position  ${READPOS} ${FILE_TO_SYNC} > ${sqlpath}/sync.sql
    if (( $? == 0 )); then
        log_info "mysqlbinlog write to ${sqlpath}/sync.sql completed"
        ls -l ${sqlpath}/sync.sql
    else
        log_info "mysqlbinlog write to ${sqlpath}/sync.sql failed and exit the mysql switch\G"
        exit 1
    fi
    if [[ LAST_BLOGFILEN != READFILE ]]; then
        count=$(cat ${LOCAL_BINLOG}.index | wc -l)
        grep -A $count ${READFILE} ${LOCAL_BINLOG}.index | grep -v ${READFILE} > ${sqlpath}/sync_file
        log_info "Need to mysqlbinlog to parse binlogfile list"
        cat ${sqlpath}/sync_file
        for i in $(cat ${sqlpath}/sync_file); do
            log_info "mysqlbinlog write to ${MYSQLBINLOG_CMD} ${i} >>${sqlpath}/sync.sql start"
            ${MYSQLBINLOG_CMD} ${i} >>${sqlpath}/sync.sql
            if (( $? == 0 )); then
                log_info "mysqlbinlog write to ${MYSQLBINLOG_CMD} ${i} >>${sqlpath}/sync.sql completed"
                ls -l ${sqlpath}/sync.sql
            else
                log_info "mysqlbinlog write to ${MYSQLBINLOG_CMD} ${i} >>${sqlpath}/sync.sql failed and exit the mysql switch\G"
                exit 1
            fi
        done
    fi
else
    log_info "The slave_io_thread is not delayed"														  
fi

# If slave sql_thread is not start and started
if [[ "${SQL_STATUS}" == "Yes" ]];then
    log_info "Slave_SQL_thread is running :${SQL_STATUS}"
else
    log_info "Slave_SQL_thread is not running :${SQL_STATUS},will start slave sql_thread" 
    ${MYSQL_REMOTE_CMD} -e "start slave sql_thread;"
    if (( $? == 0 )); then
        log_info "Slave_SQL_thread  started successfully and show slave status\G"
        ${MYSQL_REMOTE_CMD} -e "show slave status \G;"
    else
        log_info "Slave_SQL_thread  started failed and exit the mysql switch\G"
        exit 1
    fi
fi

# If slave sql_thread apply all io_thread and catch up master by execute sql file																										 
if [[ ${READFILE} == ${EXECFILE} ]] && (( ${READPOS} == ${EXECPOS} )); then
    log_info "Slave sql thread is caught up slave_readfile=${READFILE} == slave_execfile=${EXECFILE} ] && [ slave_readpost=${READPOS} == slave_execpos=${EXECPOS}"
    log_info "Set global super_read_only = OFF and start catch up master binlog file sql ${sqlpath}/sync.sql " 
    ${MYSQL_REMOTE_CMD} -N -L -s -e "set global super_read_only = OFF; set global read_only=ON; show variables like '%read_only';"
    log_info "Start execute ${sqlpath}/sync.sql"
    ls -l ${sqlpath}/sync.sql
    ${MYSQL_REMOTE_CMD} < ${sqlpath}/sync.sql
    if (( $? == 0 )); then
        log_info "Execute ${sqlpath}/sync.sql completed"
    else
        log_info "Execute ${sqlpath}/sync.sql failed and exit mysql switch"
        exit 1
    fi
else
    i=0
    while [[ ${READFILE} != ${EXECFILE} ]] || (( ${READPOS} != ${EXECPOS} )); 
	do  
        log_info "Start ${i} times sleep 5 seconds for slave sql thread to catch up slave_readfile=${READFILE} != slave_execfile=${EXECFILE} ] || [ slave_readpos=${READPOS} != slave_execpos=${EXECPOS}"
        returnstatus
        ((i++))
        if [[ ${READFILE} == ${EXECFILE} ]] && (( ${READPOS} == ${EXECPOS} )); then
            log_info "Slave sql thread is caught up slave_readfile=${READFILE} == slave_execfile=${EXECFILE} ] && [ slave_readpos=${READPOS} == slave_execpos=${EXECPOS}"
            log_info "Set global super_read_only = OFF and start catch up master binlog by sql file `ls -l ${sqlpath}/sync.sql` " 
            ${MYSQL_REMOTE_CMD} -N -L -s -e "set global super_read_only = OFF; set global read_only=ON; show variables like '%read_only';"
            ${MYSQL_REMOTE_CMD} < ${sqlpath}/sync.sql 
            if (( $? == 0 )); then
                log_info "Execute ${sqlpath}/sync.sql completed"
            else
                log_info "Execute ${sqlpath}/sync.sql failed and exit mysql switch"
                exit 1
            fi
            log_info "Set global super_read_only = OFF and  catch up master binlog  by sql file completed" 
            break
        fi
        log_info "Had ${i} times sleep 5 seconds for slave sql thread to catch up slave_readfile=${READFILE} != slave_execfile=${EXECFILE} ] || [ slave_readpos=${READPOS} != slave_execpos=${EXECPOS}"	
    done
fi

# Backuped the temp file
dates=$(date +%Y%m%d%H%M%S)
cp -a ${sqlpath}/sync.sql  ${sqlpath}/sync.sql_${dates}
cp -a ${sqlpath}/tmp.txt   ${sqlpath}/tmp.txt_${dates}
cp -a ${sqlpath}/sync_file ${sqlpath}/sync_file_${dates}